/*
 *  Copyright (C) 2011 Jaime Pavlich-Mariscal
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package cl.ucn.disc.biblio.refcluster;

import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;

import ds.tree.DuplicateKeyException;
import ds.tree.RadixTree2;
import ds.tree.RadixTree2Impl;

public class Sentence implements Comparable<Sentence> {

	private Comparator<Word> sizeComparator = new Comparator<Word>() {

		@Override
		public int compare(Word w1, Word w2) {
			if (w1.string.length() < w2.string.length()) {
				return -1;
			} else if (w1.string.length() > w2.string.length()) {
				return 1;
			} else {
				return 0;
			}
		}

	};

	private Comparator<Word> textComparator = new Comparator<Word>() {

		@Override
		public int compare(Word w1, Word w2) {
			return w1.string.compareTo(w2.string);
		}

	};

	String string;
	Queue<Word> words = new PriorityQueue<Word>(10, sizeComparator); // words
	// are
	// ordered
	// according
	// to
	// size

	Map<Sentence, Boolean> matches = new HashMap<Sentence, Boolean>();

	private RadixTree2<String> prefixTree = new RadixTree2Impl<String>();

	private MultiMap<String, Word> wordsMultiMap = new MultiMap<String, Word>();

	public Sentence(String string, String separator) {
		initialize(string, separator);
	}

	public void initialize(String string) {
		initialize(string, "\\s+");
	}
	public void initialize(String string, String separator) {
		this.string = string;
		String[] ws = separator == null? new String[] {string} : string.split(separator);
		for (String word : ws) {
			Word w = new Word(word, this);
			words.add(w);
			wordsMultiMap.add(w.string, w);

			try {
				prefixTree.insert(word, word);
			} catch (DuplicateKeyException e) {
				// nothing to do
			}
		}
	}
	
	public Sentence(String string) {
		initialize(string);
	}

	public Sentence() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * Verifies whether this sentence matches another sentence. Two sententences
	 * match if all of the words of each sentence are either a superstring or a
	 * substring of a word in the other sentence.
	 * 
	 * @param s
	 * @return
	 */
	public boolean matches(Sentence s) {
		if (words.size() == s.words.size()) {

			Set<Word> matchedWords = new LinkedHashSet<Word>(); // DO NOT USE TreeSet
			matchWords(this, s, matchedWords);
			matchWords(s, this, matchedWords);
	
			return matchedWords.size() == s.words.size() + words.size();
		} else {
			return false;
		}
	}

	private static void matchWords(Sentence s1, Sentence s2, Set<Word> matchedWords) {
		for (Word w : s1.words) {
			List<String> superStringsOfS = s2.prefixTree.searchPrefix(w.string, Integer.MAX_VALUE);//.getLeafValues(w.string);
			if (!superStringsOfS.isEmpty()) {
				matchedWords.add(w);
			}
			for (String str : superStringsOfS) {
				Set<Word> superStringWordsOfS = s2.wordsMultiMap.get(str);
				for (Word wordOfS : superStringWordsOfS) {
					matchedWords.add(wordOfS);
				}
			}
		}
	}

	@Override
	public String toString() {
//		return "Sentence [" + (words != null ? "words=" + words : "") + "]";
		return "\'" + string + "\'"; 
	}

	@Override
	public int compareTo(Sentence o) {
		return string.compareTo(o.string);
	}

}
